#include "form_setting_rtc.h"
#include "ui_form_setting_rtc.h"

// add nacessary includes here
#include "utils/configure/configure_bll.h"
#include "ui/share/form_shield_dlg.h"
#include "ui/share/form_prompt_dlg.h"


/*
 * Function:    FormSettingRTC
 * Description: The default constructor
 * Paramer:     void
 * Return:
 */
FormSettingRTC::FormSettingRTC(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::FormSettingRTC)
{
    qDebug() << Q_FUNC_INFO;

    ui->setupUi(this);
}

/*
 * FormHistoryResult:    ~FormSettingRTC
 * Description: The default destructor
 * Paramer:     void
 * Return:
 */
FormSettingRTC::~FormSettingRTC()
{
    qDebug() << Q_FUNC_INFO;

    delete ui;
}

/*
 * Function:    getInstance
 * Description: Get an instance of "FormSettingRTC" class, if exist, return it
 * Paramer:     QWidget *pParent - the pointer of QWidget class
 * Return:      the pointer of "FormSettingRTC" class
 */
FormSettingRTC* FormSettingRTC::getInstance(QWidget *pParent)
{
    static FormSettingRTC *pNew = NULL;
    if(!pNew) {
        qDebug() << Q_FUNC_INFO;

        // Create a new object if it doesn't exist
        pNew = new FormSettingRTC(pParent);
        if(NULL == pNew) return NULL;

        // After constructing object, initialize the object
        pNew->_initialze();

        // Initialize control's UI
        pNew->_initUi();

        // Hide widget firstly
        pNew->hide();
    }
    else {
        // Set the parent object
        pNew->setParent(pParent);
    }

    return pNew;
}

/*
 * Function:    _initialze
 * Description: After constructing object, initialize the object
 * Paramer:     void
 * Return:      void
 */
void FormSettingRTC::_initialze()
{
    qDebug() << Q_FUNC_INFO;

    // Signal-slot initialization
    bool bConnect = QObject::connect(this, SIGNAL(signalRefreshUI()), this, SLOT(slotRefreshUI()), Qt::AutoConnection);
    Q_ASSERT(bConnect);
}

/*
* Function:		_initUi
* Description:	Init the window style
* Paramer:		void
* Return:		void
*/
void FormSettingRTC::_initUi()
{
    qDebug() << Q_FUNC_INFO;

    // Displays the background image of the window
    QWidget::setAttribute(Qt::WA_StyledBackground);

    SET_STYLE_SHEET(QString(":/%1/setting/%2.qss").arg("skin_1").arg(this->objectName()));

    QValidator *vldDigitYear = new QRegExpValidator(QRegExp("^(20)\\d{2}$"));
    QValidator *vldDigitMonth = new QRegExpValidator(QRegExp("^0?[1-9]$|^1[0-2]$"));
    QValidator *vldDigitDay = new QRegExpValidator(QRegExp("^0?[0-9]$|^1[0-9]|^2[0-9]|^3[0-1]$"));
    QValidator *vldDigitHour = new QRegExpValidator(QRegExp("^0?[0-9]$|^1[0-9]|^2[0-3]$"));
    QValidator *vldDigitMS = new QRegExpValidator(QRegExp("^0?[0-9]$|^1[0-9]|^2[0-9]|^3[0-9]|^4[0-9]|^5[0-9]$"));
    ui->lineEdit_Year->setValidator(vldDigitYear);
    ui->lineEdit_Month->setValidator(vldDigitMonth);
    ui->lineEdit_Day->setValidator(vldDigitDay);
    ui->lineEdit_Hour->setValidator(vldDigitHour);
    ui->lineEdit_Minute->setValidator(vldDigitMS);
    ui->lineEdit_Second->setValidator(vldDigitMS);

    ui->lineEdit_Year->setInputMethodHints(Qt::ImhDigitsOnly);
    ui->lineEdit_Month->setInputMethodHints(Qt::ImhDigitsOnly);
    ui->lineEdit_Day->setInputMethodHints(Qt::ImhDigitsOnly);
    ui->lineEdit_Hour->setInputMethodHints(Qt::ImhDigitsOnly);
    ui->lineEdit_Minute->setInputMethodHints(Qt::ImhDigitsOnly);
    ui->lineEdit_Second->setInputMethodHints(Qt::ImhDigitsOnly);

    ui->lineEdit_Year->setText("2023");
    ui->lineEdit_Month->setText("01");
    ui->lineEdit_Day->setText("01");
    ui->lineEdit_Hour->setText("00");
    ui->lineEdit_Minute->setText("00");
    ui->lineEdit_Second->setText("00");

    ui->lineEdit_Year->setAlignment(Qt::AlignHCenter);
    ui->lineEdit_Month->setAlignment(Qt::AlignHCenter);
    ui->lineEdit_Day->setAlignment(Qt::AlignHCenter);
    ui->lineEdit_Hour->setAlignment(Qt::AlignHCenter);
    ui->lineEdit_Minute->setAlignment(Qt::AlignHCenter);
    ui->lineEdit_Second->setAlignment(Qt::AlignHCenter);

    this->slotRefreshUI();
}

/*
 * Function:    on_pushButton_Save_clicked
 * Description: Save configuration info
 * Paramer:     void
 * Return:      void
 */
void FormSettingRTC::on_pushButton_Save_clicked()
{
    qDebug() << Q_FUNC_INFO;

    // Prevent the button from clicking repeatedly quickly
    FormShieldDlg::getInstance(this)->show();

    int nYear = ui->lineEdit_Year->text().trimmed().toInt();
    int nMonth = ui->lineEdit_Month->text().trimmed().toInt();
    int nDay = ui->lineEdit_Day->text().trimmed().toInt();
    QString sYear = QString("%1").arg(nYear, 4, 10, QLatin1Char('0'));
    QString sMonth = QString("%1").arg(nMonth, 2, 10, QLatin1Char('0'));
    QString sDay = QString("%1").arg(nDay, 2, 10, QLatin1Char('0'));

    bool bValid = _checkValidDate(sYear + sMonth + sDay);
    if(!bValid) {
        FormPromptWidget::getInstance(this)->setPromptInfo(tr("Prompt"), tr("Date setting error"));
    }
    else {
        int nHour = ui->lineEdit_Hour->text().trimmed().toInt();
        int nMinute = ui->lineEdit_Minute->text().trimmed().toInt();
        int nSecond = ui->lineEdit_Second->text().trimmed().toInt();

        QString sDatetimeNew = QString("date -s '%1-%2-%3 %4:%5:%6'  && /sbin/hwclock -w")
                .arg(nYear)
                .arg(nMonth, 2, 10, QLatin1Char('0'))
                .arg(nDay, 2, 10, QLatin1Char('0'))
                .arg(nHour, 2, 10, QLatin1Char('0'))
                .arg(nMinute, 2, 10, QLatin1Char('0'))
                .arg(nSecond, 2, 10, QLatin1Char('0'));

        int nRetVal = ::system(sDatetimeNew.toLatin1().data());
        if(0 == nRetVal) {
            FormPromptWidget::getInstance(this)->setPromptInfo(tr("Prompt"), tr("Save successfully"));
            QTimer::singleShot(DEF_SEC_INTERVAL, this, [&]() {
                FormPromptWidget::getInstance(this)->hide();
            });
        }
        else {
            FormPromptWidget::getInstance(this)->setPromptInfo(tr("Prompt"), tr("Failed to setting datetime"));
        }
    }

    FormShieldDlg::getInstance(this)->hide();
}

void FormSettingRTC::on_pushButton_Year_Plus_clicked()
{
    qDebug() << Q_FUNC_INFO;
    int nValue = ui->lineEdit_Year->text().trimmed().toInt();

    if(2099 > nValue) {
        nValue++;
        ui->lineEdit_Year->setText(QString("%1").arg(nValue, 4, 10, QLatin1Char('0')));

        // Check the validity of the date
        _checkSpecialDate();
    }

    qDebug() << Q_FUNC_INFO << nValue;
}

void FormSettingRTC::on_pushButton_Year_Sub_clicked()
{
    qDebug() << Q_FUNC_INFO;

    int nValue = ui->lineEdit_Year->text().trimmed().toInt();

    if(2000 < nValue) {
        nValue--;
        ui->lineEdit_Year->setText(QString("%1").arg(nValue, 4, 10, QLatin1Char('0')));

        // Check the validity of the date
        _checkSpecialDate();
    }

    qDebug() << Q_FUNC_INFO << nValue;
}

void FormSettingRTC::on_pushButton_Month_Plus_clicked()
{
    qDebug() << Q_FUNC_INFO;
    int nValue = ui->lineEdit_Month->text().trimmed().toInt();

    if(0 <= nValue && 12 > nValue) {
        nValue++;
        ui->lineEdit_Month->setText(QString("%1").arg(nValue, 2, 10, QLatin1Char('0')));

        // Check the validity of the date
        _checkSpecialDate();

        qDebug() << Q_FUNC_INFO << nValue;
    }
}

void FormSettingRTC::on_pushButton_Month_Sub_clicked()
{
    qDebug() << Q_FUNC_INFO;

    int nValue = ui->lineEdit_Month->text().trimmed().toInt();

    if(1 < nValue && 12 >= nValue) {
        nValue--;
        ui->lineEdit_Month->setText(QString("%1").arg(nValue, 2, 10, QLatin1Char('0')));

        // Check the validity of the date
        _checkSpecialDate();

        qDebug() << Q_FUNC_INFO << nValue;
    }
}

void FormSettingRTC::on_pushButton_Day_Plus_clicked()
{
    qDebug() << Q_FUNC_INFO;
    int nValue = ui->lineEdit_Day->text().trimmed().toInt();

    if(0 <= nValue && 31 > nValue) {
        nValue++;
        ui->lineEdit_Day->setText(QString("%1").arg(nValue, 2, 10, QLatin1Char('0')));

        // Check the validity of the date
//        _checkSpecialDate();

        qDebug() << Q_FUNC_INFO << nValue;
    }
}

void FormSettingRTC::on_pushButton_Day_Sub_clicked()
{
    qDebug() << Q_FUNC_INFO;

    int nValue = ui->lineEdit_Day->text().trimmed().toInt();

    if(1 < nValue && 31 >= nValue) {
        nValue--;
        ui->lineEdit_Day->setText(QString("%1").arg(nValue, 2, 10, QLatin1Char('0')));

        // Check the validity of the date
//        _checkSpecialDate();

        qDebug() << Q_FUNC_INFO << nValue;
    }
}

void FormSettingRTC::on_pushButton_Hour_Plus_clicked()
{
    qDebug() << Q_FUNC_INFO;
    int nValue = ui->lineEdit_Hour->text().trimmed().toInt();

    if(0 <= nValue && 23 > nValue) {
        nValue++;
        ui->lineEdit_Hour->setText(QString("%1").arg(nValue, 2, 10, QLatin1Char('0')));

        qDebug() << Q_FUNC_INFO << nValue;
    }
}

void FormSettingRTC::on_pushButton_Hour_Sub_clicked()
{
    qDebug() << Q_FUNC_INFO;

    int nValue = ui->lineEdit_Hour->text().trimmed().toInt();

    if(0 < nValue && 23 >= nValue) {
        nValue--;
        ui->lineEdit_Hour->setText(QString("%1").arg(nValue, 2, 10, QLatin1Char('0')));

        qDebug() << Q_FUNC_INFO << nValue;
    }
}

void FormSettingRTC::on_pushButton_Minute_Plus_clicked()
{
    qDebug() << Q_FUNC_INFO;
    int nValue = ui->lineEdit_Minute->text().trimmed().toInt();

    if(0 <= nValue && 59 > nValue) {
        nValue++;
        ui->lineEdit_Minute->setText(QString("%1").arg(nValue, 2, 10, QLatin1Char('0')));

        qDebug() << Q_FUNC_INFO << nValue;
    }
}

void FormSettingRTC::on_pushButton_Minute_Sub_clicked()
{
    qDebug() << Q_FUNC_INFO;

    int nValue = ui->lineEdit_Minute->text().trimmed().toInt();

    if(0 < nValue && 59 >= nValue) {
        nValue--;
        ui->lineEdit_Minute->setText(QString("%1").arg(nValue, 2, 10, QLatin1Char('0')));

        qDebug() << Q_FUNC_INFO << nValue;
    }
}

void FormSettingRTC::on_pushButton_Second_Plus_clicked()
{
    qDebug() << Q_FUNC_INFO;
    int nValue = ui->lineEdit_Second->text().trimmed().toInt();

    if(0 <= nValue && 59 > nValue) {
        nValue++;
        ui->lineEdit_Second->setText(QString("%1").arg(nValue, 2, 10, QLatin1Char('0')));

        qDebug() << Q_FUNC_INFO << nValue;
    }
}

void FormSettingRTC::on_pushButton_Second_Sub_clicked()
{
    qDebug() << Q_FUNC_INFO;

    int nValue = ui->lineEdit_Second->text().trimmed().toInt();

    if(0 < nValue && 59 >= nValue) {
        nValue--;
        ui->lineEdit_Second->setText(QString("%1").arg(nValue, 2, 10, QLatin1Char('0')));

        qDebug() << Q_FUNC_INFO << nValue;
    }
}

/*
* Function:		slotRefreshUI
* Description:	The slot that refresh UI info
* Paramer:		void
* Return:		void
*/
void FormSettingRTC::slotRefreshUI()
{
    qDebug() << Q_FUNC_INFO;

    // Display current time
    QDateTime dtNow = QDateTime::currentDateTime();
    ui->lineEdit_Year->setText(QString("%1").arg(dtNow.date().year(), 4, 10, QLatin1Char('0')));
    ui->lineEdit_Month->setText(QString("%1").arg(dtNow.date().month(), 2, 10, QLatin1Char('0')));
    ui->lineEdit_Day->setText(QString("%1").arg(dtNow.date().day(), 2, 10, QLatin1Char('0')));
    ui->lineEdit_Hour->setText(QString("%1").arg(dtNow.time().hour(), 2, 10, QLatin1Char('0')));
    ui->lineEdit_Minute->setText(QString("%1").arg(dtNow.time().minute(), 2, 10, QLatin1Char('0')));
    ui->lineEdit_Second->setText(QString("%1").arg(dtNow.time().second(), 2, 10, QLatin1Char('0')));
}

/*
* Function:		changeEvent
* Description:	Triggers an event before it is switch language
* Paramer:		QShowEvent *event - the pointer of "QEvent"
* Return:		void
*/
void FormSettingRTC::changeEvent(QEvent *e)
{
    switch (e->type()) {
    case QEvent::LanguageChange:
    {
        ui->retranslateUi(this);
        qDebug() << Q_FUNC_INFO;
        break;
    }
    default:
        break;
    }

    QWidget::changeEvent(e);
}

/*
* Function:		_checkSpecialDate
* Description:	Check the validity of the date
* Paramer:		void
* Return:		void
*/
void FormSettingRTC::_checkSpecialDate()
{
    qDebug() << Q_FUNC_INFO;

    int nYear = ui->lineEdit_Year->text().trimmed().toInt();
    int nMonth = ui->lineEdit_Month->text().trimmed().toInt();
    int nDay = ui->lineEdit_Day->text().trimmed().toInt();

    switch(nMonth) {
    case 1:
    case 3:
    case 5:
    case 7:
    case 8:
    case 10:
    case 12:
        if(31 < nDay) nDay = 31;
        break;
    case 2:
        if(nYear % 4) {
            if(28 < nDay) nDay=28;
        }
        else {
            if(29 < nDay ) nDay = 29;
        }
        break;
    default:
        if(30 < nDay) nDay = 30;
        break;
    }

    ui->lineEdit_Day->setText(QString("%1").arg(nDay, 2, 10, QLatin1Char('0')));
    qDebug() << Q_FUNC_INFO << nYear << nMonth << nDay;
}

/*
* Function:		_checkSpecialDate
* Description:	Check the validity of the date
* Paramer:		QString sDate - the date string
* Return:		bool - is valid date
*/
bool FormSettingRTC::_checkValidDate(QString sDate)
{
    if(sDate.isEmpty()) {
        return false;
    }
    else if(8 != sDate.length()) {
        return false;
    }

     // A leap year
     bool bLeapYear = false;
     QString sYear = sDate.mid(0, 4);
     QString sMonth = sDate.mid(4, 2);
     QString sDay = sDate.mid(6, 2);

     // Determine if the year is legal
     int nYear = sYear.toInt();
     if (1900 > nYear || 2200 < nYear) {
        return false;
     }

     // Determine if it is a leap year
     if (((0 == nYear % 4) && (0 != nYear % 100)) || (0 == nYear % 400)) {
        bLeapYear = true;
     }

     // 1. Month
     if (sMonth.startsWith("0")) {
        QString units4Month = sMonth.mid(1, 1);
        int nUnits4Month = units4Month.toInt();
        if (0 == nUnits4Month) {
            return false;
        }

        if (2 == nUnits4Month) {
            // Gets the number of days in February
            int nDays4February = sDay.toInt();
            if (bLeapYear) {
                if (29 < nDays4February)
                    return false;
            }
            else {
                if (28 < nDays4February)
                    return false;
            }
        }
     }
     else {
         // 2.Determine if the month starting with non-zero is legal
         int nMonth = sMonth.toInt();
         if (10 != nMonth && 11 != nMonth && 12 != nMonth) {
            return false;
         }
     }

     // 1. Day
     if (sDay.startsWith("0")) {
         QString sUnits4Day = sDay.mid(1, 1);
         int nUnits4Day = sUnits4Day.toInt();
         if (0 == nUnits4Day) {
            return false;
        }
     }
     else {
         // 2. Determine if a non-zero date is valid
         int nDay = sDay.toInt();
         if (10 > nDay || 31 < nDay) {
            return false;
         }
     }

     if(31 == sDay.toInt() && !sMonth.contains(QRegExp("((01)|(03)|(05)|(07)|(08)|(10)|(12))"))){
        return false;
     }

      return true;
}
